export default function () {
  // 动画效果
  var canvasEl = document.querySelector("#mousedown");              // 根据ID选择器获取ID为#mousedown的canvas元素
  if (canvasEl) {
    // 如果canvas元素存在，获取其2D上下文，并设置willReadFrequently选项为true，表示上下文将频繁读取像素数据，有助于提高性能
    var ctx = canvasEl.getContext("2d", {willReadFrequently: true}) 
      , numberOfParticules = 30                                    // 初始化粒子数量、指针位置、事件类型和颜色数组等变量
      , pointerX = 0
      , pointerY = 0
      , tap = "mousedown"
      , colors = ["#FF1461", "#18FF92", "#5A87FF", "#FBF38C"]
      // 定义一个函数setCanvasSize，用于设置Canvas的大小。使用debounce函数来限制函数的执行频率即0.5秒执行一次
      , setCanvasSize = debounce(function () {
      canvasEl.width = 2 * window.innerWidth,
        canvasEl.height = 2 * window.innerHeight,            // 将Canvas的宽度和高度设置为窗口的两倍
        canvasEl.style.width = window.innerWidth + "px",   
        canvasEl.style.height = window.innerHeight + "px",   // 调整Canvas的样式以适应窗口大小
        canvasEl.getContext("2d", {willReadFrequently: true}).scale(2, 2)  // 将Canvas的2D上下文缩放2倍
    }, 500)
      , render = anime({      // 使用anime.js库初始化一个无限循环的动画
      duration: 1 / 0,        // 动画间隔设为无限，表示动画永不停止
      update: function () {   // 在update回调函数中，使用clearRect方法清除Canvas上的所有内容，为下一次绘制做准备
        ctx.clearRect(0, 0, canvasEl.width, canvasEl.height)
      }
    });
    document.addEventListener(tap, function (e) {    // 为文档添加一个鼠标按下事件的监听器
      // 当目标元素的id不是sidebar或toggle-sidebar，且元素名称不是A（超链接）或IMG（图片）时，执行以下操作
      "sidebar" !== e.target.id && "toggle-sidebar" !== e.target.id && "A" !== e.target.nodeName && "IMG" !== e.target.nodeName && (render.play(),
        updateCoords(e),                        // 更新鼠标坐标信息
        animateParticules(pointerX, pointerY))  // 根据鼠标坐标信息生成粒子动画
    }, !1),
      setCanvasSize(),                          // 设置画布大小
      window.addEventListener("resize", setCanvasSize, !1)  // 为窗口添加了一个resize事件监听器，当窗口大小改变时，再次调用setCanvasSize()函数来更新画布大小
  }
  /**
  * @author DavidLee 
  * @title updateCoords 
  * @date 2024-10-14
  * @description 更新鼠标或触摸事件发生时的坐标
  * @param  e：鼠标或触摸事件对象
  * @return null
  */
  function updateCoords(e) {
    // e.clentX和e.clientY为鼠标指针在浏览器窗口中的坐标，e.touches[0].clientX和e.touches[0].clientY为触摸屏上第一个触摸点在浏览器窗口中的坐标
    // canvasEl.getBoundingClientRect().left和canvasEl.getBoundingClientRect().top为canvas元素相对于浏览器窗口左部和顶部的距离
    pointerX = (e.clientX || e.touches[0].clientX) - canvasEl.getBoundingClientRect().left,
      pointerY = e.clientY || e.touches[0].clientY - canvasEl.getBoundingClientRect().top
  }

  /**
  * @author DavidLee 
  * @title setParticuleDirection 
  * @date 2024-10-14
  * @description 设置粒子的方向
  * @param  e：包含粒子当前位置的对象
  * @return {x, y}：粒子在x,y轴上的移动后坐标
  */
  function setParticuleDirection(e) {
    var t = anime.random(0, 360) * Math.PI / 180  // 生成随机角度，并将其转换为弧度
      , a = anime.random(50, 180)                 // 生成50~180之间随机数，表示粒子移动的距离
      , n = [-1, 1][anime.random(0, 1)] * a;      // 生成-1或1的随机数，表示粒子移动的正负方向
    return {
      x: e.x + n * Math.cos(t),                   // 返回粒子在x,y轴上的移动后坐标
      y: e.y + n * Math.sin(t)
    }
  }

  /**
  * @author DavidLee 
  * @title createParticule 
  * @date 2024-10-14
  * @description 创建一个粒子对象。这个粒子对象具有位置、颜色、半径和绘制方法等属性
  * @param  e：粒子的x坐标
  * @param  t：粒子的y坐标
  * @return a：粒子对象
  */
  function createParticule(e, t) {
    var a = {};
    return a.x = e,                                        // 设置粒子的位置
      a.y = t,
      a.color = colors[anime.random(0, colors.length - 1)],// 设置粒子的颜色
      a.radius = anime.random(16, 32),                     // 设置粒子的半径
      a.endPos = setParticuleDirection(a),                 // 设置粒子的移动方向
      // 定义粒子的绘制方法
      a.draw = function () {
        ctx.beginPath(),   // 在canvas元素的2d上下文路径上开始  
          ctx.arc(a.x, a.y, a.radius, 0, 2 * Math.PI, !0),  // 绘制一个圆
          ctx.fillStyle = a.color,                          // 设置填充颜色
          ctx.fill()
      }
      ,
      a
  }

  /**
  * @author DavidLee 
  * @title createCircle 
  * @date 2024-10-14
  * @description 创建一个圆形对象。这个圆形对象具有一些属性和方法
  * @param  e：圆形的x坐标
  * @param  t：圆形的y坐标
  * @return a：圆形对象
  */
  function createCircle(e, t) {
    var a = {};
    return a.x = e,       // 设置圆形的位置
      a.y = t,
      a.color = "#F00",   // 设置圆形的颜色
      a.radius = .1,      // 设置圆形的半径
      a.alpha = .5,       // 设置圆形的透明度
      a.lineWidth = 6,    // 设置圆形的线宽
      // 定义绘制方法
      a.draw = function () {
        ctx.globalAlpha = a.alpha,                       // 设置全局透明度
          ctx.beginPath(),                               // 在canvas元素的2d上下文路径上开始
          ctx.arc(a.x, a.y, a.radius, 0, 2 * Math.PI, !0),// 绘制一个圆
          ctx.lineWidth = a.lineWidth,                   // 设置线宽
          ctx.strokeStyle = a.color,                     // 设置边框颜色
          ctx.stroke(),                                  // 绘制边框
          ctx.globalAlpha = 1                            // 恢复全局透明度
      }
      ,
      a
  }

  /**
  * @author DavidLee 
  * @title renderParticule 
  * @date 2024-10-14
  * @description 是遍历一个动画对象（e）中的所有可动画化的元素，并调用这些元素的draw方法来绘制它们
  * @param  e：动画对象
  * @return null
  */
  function renderParticule(e) {
    for (var t = 0; t < e.animatables.length; t++)
      e.animatables[t].target.draw()  // 对每个可动画化的元素调用其draw方法来绘制该元素
  }

  /**
  * @author DavidLee 
  * @title animateParticules 
  * @date 2024-10-14
  * @description 在给定的坐标位置（e，t）上创建并动画化粒子效果
  * @param  e：粒子对象
  * @param  t：粒子的y坐标
  * @return 元素坐标
  */
  function animateParticules(e, t) {
    // 调用createCircle(e, t)函数，在给定的坐标位置创建一个初始圆
    for (var a = createCircle(e, t), n = [], i = 0; i < numberOfParticules; i++)
      // 使用一个循环，创建指定数量的粒子，并将它们存储在数组n中
      n.push(createParticule(e, t));
    anime.timeline().add({        // 使用anime.timeline()创建一个动画时间线，并添加两个动画步骤
      targets: n,                 // 第一个动画步骤针对粒子数组n，将每个粒子的位置（x和y）动画化到其结束位置
      x: function (e) {           
        return e.endPos.x
      },
      y: function (e) {
        return e.endPos.y
      },
      radius: .1,                  // 将粒子的半径动画化到0.1
      duration: anime.random(1200, 1800), // 动画持续时间为1200到1800毫秒之间的随机值
      easing: "easeOutExpo",       // 动画使用easeOutExpo缓动函数
      update: renderParticule      // 在动画更新时调用renderParticule函数来重新渲染粒子
    }).add({
      targets: a,                    // 第二个动画步骤针对初始圆a
      radius: anime.random(80, 160), // 将初始圆的半径动画化到80到160之间的随机值
      lineWidth: 0,                  // 将初始圆的线宽动画化到0
      alpha: {                       
        value: 0,                    // 将初始圆的透明度动画化到0
        easing: "linear",            // 使用线性缓动函数
        duration: anime.random(600, 800)  // 透明持续时间为600到800毫秒之间的随机值
      },
      duration: anime.random(1200, 1800), // 动画持续时间为1200到1800毫秒之间的随机值
      easing: "easeOutExpo",              // 同第一个动画
      update: renderParticule,
      offset: 0                           // 圆动画的偏移量设置为0，这意味着它将在粒子动画完成后立即开始
    })
  }

  /**
  * @author DavidLee 
  * @title debounce 
  * @date 2024-10-14
  * @description 实现防抖功能，即控制函数执行频率。通常用于限制某些频繁触发的事件（如窗口大小调整、滚动、键盘输入等）的执行次数，以优化性能和用户体验
  * @param  fn：需要防抖处理的函数
  * @param  delay：延迟时间，单位为毫秒
  * @return 加入防抖逻辑的函数
  */
  function debounce(fn, delay) {
    var timer             // 定义一个定时器变量，用于存储定时器ID
    return function () {
      var context = this
      var args = arguments
      clearTimeout(timer) // 清除之前的定时器，确保只有在最后一次调用后经过指定延迟时间才会执行fn函数，达到防抖的目的
      timer = setTimeout(function () {  // 使用setTimeout设置一个新的定时器，延迟时间为delay毫秒
        fn.apply(context, args)         // 当定时器到期时，执行函数fn，并传入当前的上下文和参数
      }, delay)
    }
  }
}
